﻿using System;
using System.Collections.Generic;

namespace Lypshare.Net.Server
{
	/// <summary>
	/// Scope.
	/// </summary>
	/// <exception cref='ArgumentNullException'>
	/// Is thrown when an argument passed to a method is invalid because it is <see langword="null" /> .
	/// </exception>
    public class Scope
    {
        // --------------------------------------------------------
        // Class Variables
        // --------------------------------------------------------


        /// <summary>
        /// The _clients.
        /// </summary>
        private List<Client> _clients
            = new List<Client>();


        /// <summary>
        /// The _name.
        /// </summary>
        private String _name = null;


        // --------------------------------------------------------
        // Class Properties
        // --------------------------------------------------------


        /// <summary>
        /// Gets the name.
        /// </summary>
        /// <value>
        /// The name.
        /// </value>
        public String Name
        {
            get { return _name; }

        } // Property: Name


        // --------------------------------------------------------
        // Class Functions
        // --------------------------------------------------------


        /// <summary>
        /// Initializes a new instance of the <see cref="Lypshare.Net.Server.Scope"/> class.
        /// </summary>
        /// <param name='name'>
        /// Name.
        /// </param>
        /// <exception cref='ArgumentNullException'>
        /// Is thrown when an argument passed to a method is invalid because it is <see langword="null" /> .
        /// </exception>
        public Scope(String name)
        {
            if (name == null)
                throw new ArgumentNullException("name");

            _name = name;

        } // Constructor


        /// <summary>
        /// Contains the specified client.
        /// </summary>
        /// <param name='client'>
        /// If set to <c>true</c> client.
        /// </param>
        /// <exception cref='ArgumentNullException'>
        /// Is thrown when an argument passed to a method is invalid because it is <see langword="null" /> .
        /// </exception>
        public bool Contains(Client client)
        {
			if(client == null)
				throw new ArgumentNullException("client");
				
            return _clients.Contains(client);

        } // Contains


        /// <summary>
        /// Synchronize the specified senderClient, receiverClient and port.
        /// </summary>
        /// <param name='senderClient'>
        /// Sender client.
        /// </param>
        /// <param name='receiverClient'>
        /// Receiver client.
        /// </param>
        /// <param name='port'>
        /// Port.
        /// </param>
        /// <exception cref='ArgumentNullException'>
        /// Is thrown when an argument passed to a method is invalid because it is <see langword="null" /> .
        /// </exception>
        /// <exception cref='InvalidOperationException'>
        /// Is thrown when an operation cannot be performed.
        /// </exception>
        public int Synchronize(Client senderClient, Client receiverClient, int port)
        {
			if(senderClient == null) throw new ArgumentNullException("senderClient");
			if(receiverClient == null) throw new ArgumentNullException("receiverClient");
			
            if (!Contains(senderClient) || !Contains(receiverClient))
                throw new InvalidOperationException("Client don't exist in scope.");

            return receiverClient.Callback
				.SyncronizeCallback(senderClient.Id, port);

        } // Synchronize


        /// <summary>
        /// Add the specified client.
        /// </summary>
        /// <param name='client'>
        /// Client.
        /// </param>
        /// <exception cref='ArgumentNullException'>
        /// Is thrown when an argument passed to a method is invalid because it is <see langword="null" /> .
        /// </exception>
        public void Add(Client client)
        {
            if (client == null)
                throw new ArgumentNullException("client");

            lock (_clients)
            {
                foreach (var receiver in _clients)
                {
                    client.Callback.BeginJoinCallback(receiver.Id, receiver.Address);
                    receiver.Callback.BeginJoinCallback(client.Id, client.Address);

                } // foreach (var receiver in _clients)

                foreach (var receiver in _clients)
                {
                    client.Callback.EndJoinCallback(receiver.Id);
                    receiver.Callback.EndJoinCallback(client.Id);

                } // foreach (var receiver in _clients)

                _clients.Add(client);

            } // lock (_clients)
        } // Add


        /// <summary>
        /// Remove the specified client.
        /// </summary>
        /// <param name='client'>
        /// Client.
        /// </param>
        /// <exception cref='ArgumentNullException'>
        /// Is thrown when an argument passed to a method is invalid because it is <see langword="null" /> .
        /// </exception>
        public void Remove(Client client)
        {
            if (client == null)
                throw new ArgumentNullException("client");
			
            lock (_clients)
            {
                if (_clients.Remove(client))
                {
                    foreach (var receiver in _clients)
                        receiver.Callback.DisconnectCallback(client.Id);

				} // if (_clients.Remove(client))
			} // lock (_clients)
		} // Remove
		
    } // class Scope
} // namespace Lypshare.Net.Server